"use strict";
import {
  Component,
  ReflectiveInjector,
  OpaqueToken,
  Inject,
  Optional
} from '@angular/core';
import { NgModule,Injectable } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

// node-gyp 需要安装 npm config set msvs_version 2013 --global

require('css/styles.css');

// 直接注入
class Car{
  public ty = `ty`;
}

// 备选的类提供商
@Injectable()
class MyService {
  getValue(): string {
    return 'a value';
  }
}

@Injectable()
class myPro{
  getValue(){}
  myProIN(){}//这个无法访问
}

// 带依赖的类提供商
@Injectable()
class Logger{
  log(data: string){ console.log(data); }
}
class UserService{ // Provider类和 provide 对象常量
  public user = {
    name: "user wei：",
    isAuthorized: true
  };
}

@Injectable()
class EvenBetterLogger extends Logger {
  constructor(private userService: UserService) { super(); }

  log(message: string) {
    let name = this.userService.user.name;
    super.log(`Message to ${name}: ${message}`);
  }
}

// 值提供商
@Injectable()
class ValueDI{
  log(){}
}

let silentLogger:any = {
  logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'],
  log: () => silentLogger.logs[0]
};

// 别名类提供商
@Injectable()
class OldLogger{
  getName():void{
    console.log("my name is wei OldLogger");
  }
  getOld(){} //这个无法访问
}
@Injectable()
class NewLogger{
  getName():void{
    console.log("my name is wei NewLogger");
  }
}

// 工厂提供商
@Injectable()
class HeroService{
  constructor(
  private logger: Logger,
  private isAuthorized?: boolean) { }

  getHeroes() {
    let auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
    this.logger.log(`Getting heroes for ${auth} user.`);
    return this.isAuthorized || false;
  }
}

let heroServiceFactory = (logger: Logger, userService: UserService) => {
  return new HeroService(logger, userService.user.isAuthorized);
};

// 非类依赖
interface AppConfig {
  apiEndpoint: string;
  title: string;
}
const HERO_DI_CONFIG: AppConfig = {
  apiEndpoint: 'api.heroes.com',
  title: 'Dependency Injection'
};
let APP_CONFIG = new OpaqueToken('app.config');

// 可选依赖
@Injectable()
class OptionalInject{
  public OptionalInjectName = "可选依赖";
}

@Component({
  selector: 'di-sample-app',
  providers: [
    // 手动ReflectiveInjector注入不需要提供商
    // .....
    // 普通提供商
    NewLogger,
    // Provider类和 provide 对象常量
    { provide: UserService, useClass: UserService },
    // 备选的类提供商
    { provide: myPro, useClass: MyService },        //这两个有点搞
    // 带依赖的类提供商
    { provide: Logger, useClass: EvenBetterLogger },
    // 值提供商
    { provide: ValueDI, useValue: silentLogger },
    // 别名类提供商
    { provide: OldLogger, useExisting: NewLogger},  //这两个有点搞,和备选类差别在于NewLogger已经在其他地方声明了
    // 工厂提供商
    { 
      provide: HeroService,
      useFactory: heroServiceFactory,
      deps: [Logger, UserService]
    },
    // 非类依赖
    { provide: APP_CONFIG, useValue: HERO_DI_CONFIG },
    // 可选依赖
    { provide: OptionalInject, useClass: OptionalInject }
  ],
  template: `
  <button (click)="invokeService()">Get Value</button>
  `
})
class DiSampleApp {
  constructor(
    public myPro: myPro,
    public logger: Logger,
    public valueDI: ValueDI,
    public newLogger: NewLogger,
    public oldLogger: OldLogger,
    public heroService: HeroService,
    @Inject(APP_CONFIG) public config: AppConfig,
    @Optional() public optionalInject: OptionalInject
  ) {}

  invokeService(): void {
    // 直接手动注入
    let injector = ReflectiveInjector.resolveAndCreate([Car]);
    console.log(injector.get(Car).ty);
    // 备选的类提供商
    console.log(this.myPro.getValue());
    // 带依赖的类提供商
    this.logger.log("Hello");
    // 值提供商
    console.log(this.valueDI.log());
    // 别名类提供商
    // 疑问：useClass和useExisting区别？
    this.oldLogger.getName();
    // 工厂提供商
    this.heroService.getHeroes();
    // 非类依赖
    console.log(this.config);
    // 可选依赖
    console.log(this.optionalInject.OptionalInjectName);
  }
}

// 启动
@NgModule({
  declarations: [ DiSampleApp ],
  imports: [ BrowserModule ],
  bootstrap: [ DiSampleApp ]
})
class DiSampleAppModule {}

platformBrowserDynamic().bootstrapModule(DiSampleAppModule);

